local UI = UI
local override_virtual = nil

function UI.CreateObject(objectType, name, inheritsFrom)
	UI.CheckArgType("CreateObject", 1, "objectType", "string", objectType)
	UI.CheckArgType("CreateObject", 2, "name", {"string", "nil"}, name)
	UI.CheckArgType("CreateObject", 3, "inheritsFrom", {"string", "nil"}, inheritsFrom)
	local class = UI.objects[objectType]
	if not class then
		error(string.format("In CreateObject(), parameter 1 (objectType) is not known frame type (%s) !", objectType))
	end
	return class:new(name, inheritsFrom)
end

function UI.InheritedCreate(result, object)
	object = object or result
	local t = UI.params[object]
	local inherit = t.inherit
	if inherit then
		if type(inherit) == "string" then
			local template =  UI.templates[inherit] or UI.fonts[inherit]
			if not template then
				log("EE Unknown Template (%s)", inherit)
			else
				UI.InheritedCreate(result, template)
			end
		else
			for _, i in ipairs(inherit) do
				local template =  UI.templates[i] or UI.fonts[inherit]
				if not template then
					log("EE Unknown Template (%s)", i)
				else
					UI.InheritedCreate(result, template)
				end
			end
		end
	end
	local virtual = t.virtual
	if virtual then
		if virtual.parent and not t.parent then
			UI.Reparent(result, virtual.parent)
		end
		if not UI.IsWidgetType(result, t.type) then
			log("EE Invalid Template: (%q of type %q) is used as a template for (%q of type %q)", t.name, t.type, UI.params[result].name or "*nil*", UI.params[result].type)
		end
		if virtual.onFrameCreate then
			local previous = override_virtual
			override_virtual = true
			local log = log
			api.call(function ()
				local status, error = pcall(virtual.onFrameCreate, result)
				if not status then
					log("EE Error in Template instancing: %s", error)
				end
			end)
			override_virtual = previous
		end
	end
end

function UI.SetFrameProtected(frame)
	UI.params[frame].protected = true
end

if config.DELAY_ONLOAD then
	UI.framesToLoad = {}
end

local function newFrame(funcName, frameType, name, parent, inheritFrame, id, onFrameCreate)
	UI.CheckArgType(funcName, 1, "frameType", "string", frameType)
	UI.CheckArgType(funcName, 2, "name", {"string", "nil"}, name)
	if parent and type(parent) == "string" then
		local p = UI.GetGlobal(parent)
		if p then
			parent = p
		else
			error(string.format("In %s(), parameter 3 is a unknown parent (%q) !", funcName, parent))
		end
	end
	if parent then
		UI.CheckArgWidget(funcName, 3, "parent", "Frame", parent)
	end
	UI.CheckArgType(funcName, 4, "inheritFrame", {"string", "nil"}, inheritFrame)
	local class = UI.objects[frameType]
	if not class or class.virtual then
		error(string.format("In %s(), parameter 1 (frameType) is not known frame type (%s) !", funcName, frameType))
	end
	local f = class:new(name, inheritFrame)
	if parent then
		UI.Reparent(f, parent)
	end
	if id then
		f:SetID(id)
	end
	if name then
		UI.SetGlobal(name, f)
	end
	UI.InheritedCreate(f)
	if id then
		f:SetID(id)
	end
	if onFrameCreate then
		api.call(function () onFrameCreate(f) end)
	end
	if config.DELAY_ONLOAD then
		UI.framesToLoad[f] = true
	else
		UI.CallScript(f, "OnLoad")
	end
	return f
end


function UI.CreateFrame(frameType, name, parent, inheritFrame)
	return newFrame("CreateFrame", frameType, name, parent, inheritFrame)
end

function UI.RegisterFrame(virtual, type, name, parent, inherits, id, callback)
	if virtual and not override_virtual then
		-- this function is from emulator only
		UI.RegisterVirtualFrame(type, name, parent, inherits, id, callback)
	else
		UI.RegisterRealFrame(type, name, parent, inherits, id, callback)
	end
end

function UI.RegisterFont(name, inheritFrame, onFrameCreate)
	UI.CheckArgType("RegisterFont", 1, "name", "string", name)
	UI.CheckArgType("RegisterFont", 2, "inheritFrame", {"string", "nil"}, inheritFrame)
	local f = UI.objects.Font:new(name, inheritFrame)
	local t = UI.params[f]
	t.virtual = {
		onFrameCreate = onFrameCreate,
	}
	UI.fonts[name] = f
	UI.SetGlobal(name, f)

	return f
end

function UI.RegisterRealFrame(frameType, name, parent, inheritFrame, id, onFrameCreate)
	return newFrame("RegisterRealFrame", frameType, name, parent, inheritFrame, id, onFrameCreate)
end

function UI.RegisterVirtualFrame(frameType, name, parent, inheritFrame, id, onFrameCreate)
	UI.CheckArgType("RegisterVirtualFrame", 1, "frameType", "string", frameType)
	UI.CheckArgType("RegisterVirtualFrame", 2, "name", {"string", "nil"}, name)
	if parent then
		if type(parent) ~= "string" then
			UI.CheckArgWidget("RegisterVirtualFrame", 3, "parent", "Frame", parent)
		end
	end
	UI.CheckArgType("RegisterVirtualFrame", 4, "inheritFrame", {"string", "nil"}, inheritFrame)
	local class = UI.objects[frameType]
	if not class then
		error(string.format("In RegisterVirtualFrame(), parameter 1 (frameType) is not known frame type (%s) !", frameType))
	end
	local f = class:new(name, inheritFrame)
	local t = UI.params[f]
	t.virtual = {
		parent = parent,
		onFrameCreate = onFrameCreate,
		id = id,
	}
	UI.templates[name] = f
	return f
end

function UI.CallDeferredOnLoad()
	if not UI.framesToLoad then return end
	local f = next(UI.framesToLoad)
	while f do
		UI.CallScript(f, "OnLoad")
		f = next(UI.framesToLoad)
	end
end

local last_time = os.clock()
local updating = false
function UI.Update(delta)
	if updating then return end
	UI.CallDeferredOnLoad()
	updating = true
	local time = os.clock()
	local elapsed = last_time - time
	if delta then
		elapsed = elapsed + delta
	end
	for _, t in pairs(UI.params) do
		if not t.virtual then
			if t.visible then
--~ 				if not t.last_shown and UI.Visible(frame) then
--~ 					UI.CallScript(frame, "OnShow")
--~ 					t.last_shown = true
--~ 				end
				UI.CallScript(t.self, "OnUpdate", elapsed)
--~ 			elseif t.last_shown then
--~ 				UI.CallScript(frame, "OnHide")
--~ 				t.last_shown = nil
			end
		end
	end
	last_time = time
	updating = false
end

